package com.apes.scm.stock.transfer.service;

import com.apes.framework.api.DomainService;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.util.Arith;
import com.apes.framework.util.MapUtil;
import com.apes.scm.account.method.Batch;
import com.apes.scm.account.method.BatchMethod;
import com.apes.scm.sal.saleOrder.SaleOrder;
import com.apes.scm.sal.saleOrder.SaleOrderItem;
import com.apes.scm.sal.saleReturn.SaleReturn;
import com.apes.scm.sal.saleReturn.SaleReturnItem;
import com.apes.scm.sal.saleReturn.SaleReturnRepository;
import com.apes.scm.voucher.model.Voucher;
import com.apes.scm.voucher.model.VoucherInventory;
import com.apes.scm.voucher.model.VoucherItem;
import com.apes.scm.voucher.repository.VoucherInventoryRepository;
import com.apes.scm.voucher.repository.VoucherRepository;
import com.apes.scm.voucher.service.BusinessType;
import com.apes.scm.voucher.service.VoucherType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;

import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

import static java.lang.Math.abs;

@Service("pickFlowSaleReturnVoucherService")
public class PickFlowSaleReturnVoucherService extends DomainService {

    @Autowired
    private SaleReturnRepository saleReturnRepository;
    @Autowired
    private VoucherRepository voucherRepository;
    @Autowired
    private VoucherInventoryRepository voucherInventoryRepository;

    public Voucher test(SimpleRequest simpleRequest){
        String id = simpleRequest.get("id");
        SaleReturn saleReturn = saleReturnRepository.findOne(id);
        return process(saleReturn);
    }

    /**
     * 分销退货创建凭证
     *
     * @param simpleRequest SaleReturn
     * @return
     */
    public Voucher flowSaleOrderVoucher(SimpleRequest simpleRequest) {
        SaleReturn saleReturn = saleReturnRepository.findOne(simpleRequest.getO(SaleReturn.class).getId());
        if (saleReturn == null) throw new RuntimeException("退货订单不存在！");
        return process(saleReturn);
    }

    private Voucher process(SaleReturn saleReturn) {
        // 区分是否有单退货与无原单退货
        if ("A".equals(saleReturn.getOrderType().getCode())) {   // 有原单
            // 数据检查
            SaleOrder saleOrder = saleReturn.getSaleOrder();
            if (saleOrder == null) throw new RuntimeException("有原单退货业务，原单不允许为空！");

            if (Objects.equals("one", saleReturn.getSaleOrder().getMoveType().getId())) {
                return returnWithOrder(saleReturn);         // 一次性发货
            } else {
                return returnWithOrderBatch(saleReturn);   // 部分发货
            }

        } else {
            // 无原单
            return returnNoOrder(saleReturn);
        }
    }


    private Voucher returnNoOrder(SaleReturn saleReturn) {
        Voucher voucher = getVoucher(saleReturn);

        // 明细处理
        Set<VoucherItem> voucherItems = new HashSet();
        saleReturn.getSaleReturnItems().forEach(
                saleReturnItem -> {
                    VoucherItem voucherItem = getVoucherItem(saleReturn, saleReturnItem);
                    voucherItems.add(voucherItem);
                });
        voucher.setVoucherItems(voucherItems);
        return voucher;
    }


    private Voucher returnWithOrder(SaleReturn saleReturn) {
        Voucher voucher = getVoucher(saleReturn);
        SaleReturnItem returnItem = saleReturn.getSaleReturnItems().iterator().next();

        // 添加原销售凭证信息
        Voucher originSaleVoucher;
        if (saleReturn.getSaleOrder().getScene() == null) {
            // 内协产生分销单，定损产生分销单无场景流
            originSaleVoucher = voucherRepository.findSaleVoucherByCompanyAndItemSource(saleReturn.getCompany(),
                    saleReturn.getCustomer().getParty().getPartyRoleByType("Customer"), returnItem.getSaleOrderItem().getId());
            voucher.setVoucher(originSaleVoucher);

            // 增加凭证分类
            if ("RETAIL_SALE".equals(saleReturn.getSaleOrder().getOrderType())) {
                voucher.setClassification(VoucherType.INSURANCE);
            }

        } else {
            originSaleVoucher = voucherRepository.findSaleVoucherByCompanyAndItemOrigin(saleReturn.getCompany(),
                    saleReturn.getCustomer().getParty().getPartyRoleByType("Customer"), returnItem.getSaleOrderItem().getId());
            voucher.setVoucher(originSaleVoucher);
        }

        // 明细处理
        Set<VoucherItem> voucherItems = new HashSet();
        saleReturn.getSaleReturnItems().forEach(
                saleReturnItem -> {
                    VoucherItem voucherItem = getVoucherItem(saleReturn, saleReturnItem);
                    voucherItem.setVoucher(voucher);
                    // 获取原销售凭证明细
                    SaleOrderItem saleOrderItem = saleReturnItem.getSaleOrderItem();
                    VoucherItem saleVoucherItem = voucherItem.findVoucherItem(saleOrderItem.getId());
                    if (saleVoucherItem == null)
                        throw new RuntimeException("没有找到原单明细：" + saleOrderItem.getId() + " 的业务凭证！");

                    voucherItem.setSaleCommission( -1 * saleVoucherItem.getSaleCommission());
                    voucherItem.setVoucherItem(saleVoucherItem);
                    voucherItems.add(voucherItem);

                });
        voucher.setVoucherItems(voucherItems);
        return voucher;
    }

    /**
     * 根据批次退货
     *
     * @param saleReturn
     * @return
     */
    private Voucher returnWithOrderBatch(SaleReturn saleReturn) {
        Voucher voucher = getVoucher(saleReturn);

        // 明细处理
        Set<VoucherItem> vis = new HashSet();
        saleReturn.getSaleReturnItems().forEach(item ->
                new BatchMethod<Batch>() {

                    @Override
                    public Iterable<Batch> wrap() {
                        return voucherInventoryRepository.findInventoryBatchForMultiSaleReturn(saleReturn.getCompany(), saleReturn.getCustomer(),
                                item.getProduct(), saleReturn.getSaleOrder().getId(), PageRequest.of(0, 100))
                                .getContent().stream()
                                .filter(vib -> vib.getProductQty() - vib.getQtyReturned() - vib.getFrostQty() > 0)
                                .map(vib -> {
                                    Batch batch = new Batch();
                                    batch.setEntity(vib);
                                    double returnableQty = vib.getProductQty() - vib.getQtyReturned() - vib.getFrostQty();
                                    double qty = vib.getUom().computeQty(returnableQty, item.getUom(), true);
                                    batch.setQty(qty);
                                    return batch;
                                }).collect(Collectors.toList());
                    }

                    @Override
                    public void succeed(Batch batch, double increment) {
                        VoucherInventory vib = (VoucherInventory) batch.getEntity();
                        double qty = item.getUom().computeQty(increment, vib.getUom(), true);
                        vib.changeFrostQty(qty);

                        VoucherItem vi = new VoucherItem();
                        vi.setVoucher(voucher);

                        vi.setProduct(item.getProduct());
                        vi.setTax(vib.getTax());
                        vi.setUom(item.getUom());
                        vi.setPriceUnit(item.getPriceUnit());
                        vi.setProductQty(-1 * abs(increment));
                        vi.setOriginItemId(item.getSaleOrderItem().getId());
                        vi.setSourceItemId(item.getId());
                        vi.setVoucherItem(vib.getVoucherItem());

                        double saleCommission = Arith.round(vib.getVoucherItem().getSaleCommission() / vib.getVoucherItem().getProductQty(), 4);
                        vi.setSaleCommission( -1 * saleCommission * abs(increment));

                        vis.add(vi);
                    }

                    @Override
                    public void error(double surplus) {
                        throw new RuntimeException("分销多次发货时，商品：["+ item.getProduct().getId() +"]" + item.getProduct().getName() + " 价值库存数量少 " + surplus + item.getUom().getName() + "！");
                    }
                }.execute(Math.abs(item.getProductUomQty()))
        );
        voucher.setVoucherItems(vis);

        return voucher;
    }

    private Voucher getVoucher(SaleReturn saleReturn) {
        // 主表信息
        Voucher voucher = new Voucher();
        voucher.setReturned(true);
        voucher.setBusinessType(BusinessType.SALE_RETURN);

        voucher.setPartner(saleReturn.getCustomer());
        voucher.setCompany(saleReturn.getCompany());
        voucher.setDept(saleReturn.getDept());

        voucher.setContract(saleReturn.getContract());
        voucher.setInventoryMode(saleReturn.getCooperation().getInventoryMode());
        voucher.setAccountingMethod(saleReturn.getCooperation().getAccountingMethod());

        voucher.setClerk(saleReturn.getClerk());
        voucher.setScene(saleReturn.getScene());
        voucher.setOrigin(saleReturn.getId());
        voucher.setOriginBusinessType(saleReturn.getInnerBusinessType());
        voucher.setSource(saleReturn.getId());
        voucher.setSourceBusinessType(saleReturn.getInnerBusinessType());
        return voucher;
    }

    private VoucherItem getVoucherItem(SaleReturn saleReturn, SaleReturnItem saleReturnItem) {
        VoucherItem voucherItem = new VoucherItem();
        voucherItem.setProduct(saleReturnItem.getProduct());
        voucherItem.setTax(saleReturnItem.getTax());
        voucherItem.setOwner(saleReturn.getLocation().getCompany());

        // 设置为销售的单位以及单价(退货价格设置为负数)
        voucherItem.setUom(saleReturnItem.getUom());
        voucherItem.setProductQty(-1.00 * saleReturnItem.getProductUomQty());
        voucherItem.setPriceUnit(saleReturnItem.getPriceUnit());

        voucherItem.setOriginItemId(saleReturnItem.getId());
        voucherItem.setSourceItemId(String.valueOf(saleReturnItem.getId()));
        voucherItem.setSupplier(saleReturnItem.getSupplier());
        return voucherItem;
    }
}
